{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: Types\n",
    "sidebar_position: 1\n",
    "description: Standard Mojo data types.\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All values in Mojo have an associated data type. Most of the types are\n",
    "_nominal_ types, defined by a [`struct`](/mojo/manual/structs). These types are\n",
    "nominal (or \"named\") because type equality is determined by the type's _name_,\n",
    "not its _structure_.\n",
    "\n",
    "There are a some types that aren't defined as structs:\n",
    "\n",
    "* Functions are typed based on their signatures.\n",
    "* `NoneType` is a type with one instance, the `None` object, which is used to\n",
    "  signal \"no value.\"\n",
    "\n",
    "Mojo comes with a standard library that provides a number of useful types and\n",
    "utility functions. These standard types aren’t privileged. Each of the standard\n",
    "library types is defined just like user-defined types—even basic types like \n",
    "[`Int`](/mojo/stdlib/builtin/int/Int) and \n",
    "[`String`](/mojo/stdlib/builtin/string/String). But these standard library types\n",
    "are the building blocks you'll use for most Mojo programs.\n",
    "\n",
    "The most common types are _built-in types_, which are always available and\n",
    "don't need to be imported. These include types for numeric values, strings,\n",
    "boolean values, and others.\n",
    "\n",
    "The standard library also includes many more types that you can import as\n",
    "needed, including collection types, utilities for interacting with the\n",
    "filesystem and getting system information, and so on.\n",
    "\n",
    "## Numeric types\n",
    "\n",
    "Mojo's most basic numeric type is `Int`, which represents a signed integer of\n",
    "the largest size supported by the system—typically 64 bits or 32 bits.\n",
    "\n",
    "Mojo also has built-in types for integer and floating-point values of various\n",
    "precisions:\n",
    "\n",
    "<figure id=\"table-1\">\n",
    "\n",
    "| Type name     | Description  |\n",
    "|---------------|--------------|\n",
    "| `Int8`        | 8-bit signed integer |\n",
    "| `UInt8`       | 8-bit unsigned integer |\n",
    "| `Int16`       | 16-bit signed integer |\n",
    "| `UInt16`      | 16-bit unsigned integer |\n",
    "| `Int32`       | 32-bit signed integer |\n",
    "| `UInt32`      | 32-bit unsigned integer |\n",
    "| `Int64`       | 64-bit signed integer |\n",
    "| `UInt64`      | 64-bit unsigned integer |\n",
    "| `Float16`     | 16-bit floating point number (IEEE 754-2008 binary16) |\n",
    "| `Float32`     | 32-bit floating point number (IEEE 754-2008 binary32) |\n",
    "| `Float64`     | 64-bit floating point number (IEEE 754-2008 binary64) |\n",
    "<figcaption><b>Table 1.</b> Numeric types with specific precision</figcaption>\n",
    "</figure>\n",
    "\n",
    "The types in Table 1 are actually all aliases to a single type, \n",
    "[`SIMD`](/mojo/stdlib/builtin/simd/SIMD), which is discussed later.\n",
    "\n",
    "All of the numeric types support the usual numeric and bitwise operators. The \n",
    "[`math`](/mojo/stdlib/math/) module provides a number of additional math\n",
    "functions.\n",
    "\n",
    "You may wonder when to use `Int` and when to use the other integer \n",
    "types. In general, `Int` is good safe default when you need an integer type and\n",
    "you don't require a specific bit width. Using `Int` as the default integer type\n",
    "for APIs makes APIs more consistent and predictable.\n",
    "\n",
    "\n",
    "### Floating-point numbers\n",
    "\n",
    "Floating-point types represent real numbers. Because not all real numbers can be\n",
    "expressed in a finite number of bits, floating-point numbers can't represent\n",
    "every value exactly.\n",
    "\n",
    "The floating-point types listed in Table 1—`Float64`, `Float32`, and \n",
    "`Float16`—follow the IEEE 754-2008 standard for representing floating-point \n",
    "values. Each type includes a sign bit, one set of bits representing an exponent,\n",
    "and another set representing the fraction or mantissa. Table 2 shows how each of \n",
    "these types are represented in memory.\n",
    "\n",
    "<figure>\n",
    "\n",
    "| Type name  | Sign  | Exponent  | Mantissa |\n",
    "|------------|-------|-----------|----------|\n",
    "| `Float64`  | 1 bit | 11 bits   | 52 bits  |\n",
    "| `Float32`  | 1 bit | 8 bits    | 23 bits  |\n",
    "| `Float16`  | 1 bit | 5 bits    | 10 bits  |\n",
    "<figcaption><b>Table 2.</b> Details of floating-point types</figcaption>\n",
    "</figure>\n",
    "\n",
    "Numbers with exponent values of all ones or all zeros represent special values,\n",
    "allowing floating-point numbers to represent infinity, negative infinity,\n",
    "signed zeros, and not-a-number (NaN). For more details on how numbers are\n",
    "represented, see [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) on\n",
    "Wikipedia.\n",
    "\n",
    "A few things to note with floating-point values:\n",
    "\n",
    "- Rounding errors. Rounding may produce unexpected results. For example, 1/3\n",
    "  can't be represented exactly in these floating-point formats. The more\n",
    "  operations you perform with floating-point numbers, the more the rounding\n",
    "  errors accumulate. \n",
    "\n",
    "- Space between consecutive numbers. The space between consecutive numbers is\n",
    "  variable across the range of a floating-point number format. For numbers close\n",
    "  to zero, the distance between consecutive numbers is very small. For large\n",
    "  positive and negative numbers, the space between consecutive numbers is\n",
    "  greater than 1, so it may not be possible to represent consecutive integers.\n",
    "\n",
    "Because the values are approximate, it is rarely useful to compare them with\n",
    "the equality operator (`==`). Consider the following example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "var big_num = 1.0e16\n",
    "var bigger_num = big_num+1.0\n",
    "print(big_num == bigger_num)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Comparison operators (`<` `>=` and so on) work with floating point numbers. You\n",
    "can also use the [`math.isclose()`](/mojo/stdlib/math/math/isclose) function to\n",
    "compare whether two floating-point numbers are equal within a specified\n",
    "tolerance."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Numeric literals\n",
    "\n",
    "In addition to these numeric types, the standard libraries provides integer and\n",
    "floating-point literal types, \n",
    "[`IntLiteral`](/mojo/stdlib/builtin/int_literal/IntLiteral) and \n",
    "[`FloatLiteral`](/mojo/stdlib/builtin/float_literal/FloatLiteral).\n",
    "\n",
    "These literal types are used at compile time to represent literal numbers that\n",
    "appear in the code. In general, you should never instantiate these types\n",
    "yourself.\n",
    "\n",
    "Table 3 summarizes the literal formats you can use to represent numbers.\n",
    "\n",
    "<figure>\n",
    "\n",
    "| Format | Examples | Notes |\n",
    "|--------|---------|-------|\n",
    "| Integer literal | `1760` | Integer literal, in decimal format. |\n",
    "| Hexadecimal literal | `0xaa`, `0xFF` | Integer literal, in hexadecimal format.<br />Hex digits are case-insensitive. |\n",
    "| Octal literal | `0o77` | Integer literal, in octal format. |\n",
    "| Binary literal | `0b0111` | Integer literal, in binary format. |\n",
    "| Floating-point literal | `3.14`, `1.2e9` | Floating-point literal.<br />Must include the decimal point to be interpreted as floating-point. |\n",
    "<figcaption><b>Table 3.</b> Numeric literal formats</figcaption>\n",
    "</figure>\n",
    "\n",
    "At compile time, the literal types are arbitrary-precision (also called \n",
    "infinite-precision) values, so the compiler can perform compile-time \n",
    "calculations without overflow or rounding errors.\n",
    "\n",
    "At runtime the values are converted to finite-precision types—`Int` for\n",
    "integer values, and `Float64` for floating-point values. (This process of \n",
    "converting a value that can only exist at compile time into a runtime value is\n",
    "called _materialization_.) \n",
    "\n",
    "The following code sample shows the difference between an arbitrary-precision \n",
    "calculation and the same calculation done using `Float64` values at runtime,\n",
    "which suffers from rounding errors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.0 0.99999999999999978\n"
     ]
    }
   ],
   "source": [
    "var arbitrary_precision = 3.0 * (4.0 / 3.0 - 1.0)\n",
    "# use a variable to force the following calculation to occur at runtime\n",
    "var three = 3.0\n",
    "var finite_precision = three * (4.0 / three - 1.0)\n",
    "print(arbitrary_precision, finite_precision)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### `SIMD` and `DType`\n",
    "\n",
    "To support high-performance numeric processing, Mojo uses the\n",
    "[`SIMD`](/mojo/stdlib/builtin/simd/SIMD) type as the basis for its numeric\n",
    "types. SIMD (single instruction, multiple data) is a processor technology that\n",
    "allows you to perform an operation on an entire set of operands at once. Mojo's\n",
    "`SIMD` type abstracts SIMD operations. A `SIMD` value represents a SIMD\n",
    "_vector_—that is, a fixed-size array of values that can fit into a processor's\n",
    "register. SIMD vectors are defined by two\n",
    "[_parameters_](/mojo/manual/parameters/):\n",
    "\n",
    "- A `DType` value, defining the data type in the vector (for example, \n",
    "  32-bit floating-point numbers).\n",
    "- The number of elements in the vector, which must be a power of two.\n",
    "\n",
    "For example, you can define a vector of four `Float32` values like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "var vec = SIMD[DType.float32, 4](3.0, 2.0, 2.0, 1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Math operations on SIMD values are \n",
    "applied _elementwise_, on each individual element in the vector. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 6, 15, 28]\n"
     ]
    }
   ],
   "source": [
    "var vec1 = SIMD[DType.int8, 4](2, 3, 5, 7)\n",
    "var vec2 = SIMD[DType.int8, 4](1, 2, 3, 4)\n",
    "var product = vec1 * vec2\n",
    "print(product)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "### Scalar values\n",
    "\n",
    "The `SIMD` module defines several _type aliases_ that are shorthand for\n",
    "different types of `SIMD` vectors. In particular, the `Scalar` type is just a\n",
    "`SIMD` vector with a single element. The numeric types listed in \n",
    "[Table 1](#table-1), like `Int8` and `Float32` are actually type aliases for\n",
    "different types of scalar values:\n",
    "\n",
    "```mojo\n",
    "alias Scalar = SIMD[size=1]\n",
    "alias Int8 = Scalar[DType.int8]\n",
    "alias Float32 = Scalar[DType.float32]\n",
    "```\n",
    "\n",
    "This may seem a little confusing at first, but it means that whether you're \n",
    "working with a single `Float32` value or a vector of float32 values,\n",
    "the math operations go through exactly the same code path."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### The `DType` type\n",
    "\n",
    "The `DType` struct describes the different data types that a `SIMD` vector can\n",
    "hold, and defines a number of utility functions for operating on those data\n",
    "types. The `DType` struct defines a set of aliases that act as identifiers for\n",
    "the different data types, like `DType.int8` and `DType.float32`. You use\n",
    "these aliases when declaring a `SIMD` vector:\n",
    "\n",
    "```mojo\n",
    "var v: SIMD[DType.float64, 16]\n",
    "```\n",
    "\n",
    "Note that `DType.float64` isn't a _type_, it's a value that describes a data\n",
    "type. You can't create a variable with the type `DType.float64`. You can create\n",
    "a variable with the type `SIMD[DType.float64, 1]` (or  `Float64`, which is the\n",
    "same thing).\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "float32 is floating point: True\n",
      "float32 is integral: False\n",
      "Min/max finite values for float32\n",
      "-3.4028234663852886e+38 3.4028234663852886e+38\n"
     ]
    }
   ],
   "source": [
    "from utils.numerics import max_finite, min_finite\n",
    "\n",
    "def describeDType[dtype: DType]():\n",
    "    print(dtype, \"is floating point:\", dtype.is_floating_point())\n",
    "    print(dtype, \"is integral:\", dtype.is_integral())\n",
    "    print(\"Min/max finite values for\", dtype)\n",
    "    print(min_finite[dtype](), max_finite[dtype]())\n",
    "\n",
    "describeDType[DType.float32]()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "There are several other data types in the standard library that also use\n",
    "the `DType` abstraction. \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Strings\n",
    "\n",
    "Mojo's `String` type represents a mutable string. (For Python programmers, note\n",
    "that this is different from Python's standard string, which is immutable.)\n",
    "Strings support a variety of operators and common methods.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Testing Mojo strings\n"
     ]
    }
   ],
   "source": [
    "var s: String = \"Testing\"\n",
    "s += \" Mojo strings\"\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most standard library types conform to the \n",
    "[`Stringable`](/mojo/stdlib/builtin/str/Stringable) trait, which represents\n",
    "a type that can be converted to a string. Use `str(value)` to\n",
    "explicitly convert a value to a string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Items in list: 5\n"
     ]
    }
   ],
   "source": [
    "var s = str(\"Items in list: \") + str(5)\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### String literals\n",
    "\n",
    "As with numeric types, the standard library includes a string literal type used\n",
    "to represent literal strings in the program source. String literals are\n",
    "enclosed in either single or double quotes.\n",
    "\n",
    "Adjacent literals are concatenated together, so you can define a long string\n",
    "using a series of literals broken up over several lines:\n",
    "\n",
    "```\n",
    "var s = \"A very long string which is \"\n",
    "        \"broken into two literals for legibility.\"\n",
    "```\n",
    "\n",
    "To define a multi-line string, enclose the literal in three single or double\n",
    "quotes:\n",
    "\n",
    "```\n",
    "var s = \"\"\"\n",
    "Multi-line string literals let you \n",
    "enter long blocks of text, including \n",
    "newlines.\"\"\"\n",
    "```\n",
    "\n",
    "Note that the triple double quote form is also used for API documentation\n",
    "strings.\n",
    "\n",
    "Unlike `IntLiteral` and `FloatLiteral`, `StringLiteral` doesn't automatically\n",
    "materialize to a runtime type. In some cases, you may need to manually convert\n",
    "`StringLiteral` values to `String` using the built-in \n",
    "[`str()`](/mojo/stdlib/builtin/str/str) method. \n",
    "\n",
    "For example, if you want to concatenate string literals to other types, you need \n",
    "to first convert `StringLiteral` to `String` values. This is because many types\n",
    "can be implicitly converted to `String`, but not to `StringLiteral`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Strings play nicely with others: True\n"
     ]
    }
   ],
   "source": [
    "# print(\"Strings play nicely with others: \" + True)\n",
    "# Error: ... right hand side cannot be converted from Bool to StringLiteral\n",
    "print(str(\"Strings play nicely with others: \") + str(True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "\n",
    "## Booleans\n",
    "\n",
    "Mojo's `Bool` type represents a boolean value. It can take one of two values, \n",
    "`True` or `False`. You can negate a boolean value using the `not` operator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False True\n"
     ]
    }
   ],
   "source": [
    "var conditionA = False\n",
    "var conditionB: Bool\n",
    "conditionB = not conditionA\n",
    "print(conditionA, conditionB)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Many types have a boolean representation. Any type that implements the \n",
    "[`Boolable`](/mojo/stdlib/builtin/bool/Boolable) trait has a boolean \n",
    "representation. As a general principle, collections evaluate as True if they \n",
    "contain any elements, False if they are empty; strings evaluate as True if they\n",
    "have a non-zero length."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Collection types\n",
    "\n",
    "The Mojo standard library also includes a set of basic collection types that\n",
    "can be used to build more complex data structures:\n",
    "\n",
    "- [`List`](/mojo/stdlib/collections/list/List), a dynamically-sized array of \n",
    "  items.\n",
    "- [`Dict`](/mojo/stdlib/collections/dict/Dict), an associative array of \n",
    "  key-value pairs.\n",
    "- [`Set`](/mojo/stdlib/collections/set/Set), an unordered collection of unique\n",
    "  items.\n",
    "- [`Optional`](/mojo/stdlib/collections/optional/Optional)\n",
    "  represents a value that may or may not be present. \n",
    "\n",
    "The collection types are _generic types_: while a given collection can only\n",
    "hold a specific type of value (such as `Int` or `Float64`), you specify the\n",
    "type at compile time using a [parameter](/mojo/manual/parameters/). For\n",
    "example, you can create a `List` of `Int` values like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "var l = List[Int](1, 2, 3, 4)\n",
    "# l.append(3.14) # error: FloatLiteral cannot be converted to Int"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You don't always need to specify the type explicitly. If Mojo can _infer_ the\n",
    "type, you can omit it. For example, when you construct a list from a set of \n",
    "integer literals, Mojo creates a `List[Int]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Inferred type == Int\n",
    "var l1 = List(1, 2, 3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Where you need a more flexible collection, the \n",
    "[`Variant`](/mojo/stdlib/utils/variant/Variant) type can hold different types \n",
    "of values. For example, a `Variant[Int32, Float64]` can hold either an `Int32`\n",
    "_or_ a `Float64` value at any given time. (Using `Variant` is not covered in\n",
    "this section, see the [API docs](/mojo/stdlib/utils/variant/Variant) for more\n",
    "information.)\n",
    "\n",
    "The following sections give brief introduction to the main collection types. \n",
    "\n",
    "### List\n",
    "\n",
    "[`List`](/mojo/stdlib/collections/list/List) is a dynamically-sized array of \n",
    "elements. List elements need to conform to the \n",
    "[`CollectionElement`](/mojo/stdlib/builtin/value/CollectionElement) trait, which\n",
    "just means that the items must be copyable and movable. Most of the common\n",
    "standard library primitives, like `Int`, `String`, and `SIMD` conform to this\n",
    "trait. You can create a `List` by passing the element type as a parameter,  like\n",
    "this:\n",
    "\n",
    "\n",
    "```mojo\n",
    "var l = List[String]()\n",
    "```\n",
    "\n",
    "The `List` type supports a subset of the Python `list` API, including the\n",
    "ability to append to the list, pop items out of the list, and access list items\n",
    "using subscript notation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Popping last item from list:  11\n",
      "2, 3, 5, 7, "
     ]
    }
   ],
   "source": [
    "from collections import List\n",
    "\n",
    "var list = List(2, 3, 5)\n",
    "list.append(7)\n",
    "list.append(11)\n",
    "print(\"Popping last item from list: \", list.pop())\n",
    "for idx in range(len(list)):\n",
    "      print(list[idx], end=\", \")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the previous code sample leaves out the type parameter when creating \n",
    "the list. Because the list is being created with a set of `Int` values, Mojo can\n",
    "_infer_ the type from the arguments. \n",
    "\n",
    "There are some notable limitations when using `List`:\n",
    "\n",
    "- You can't currently initialize a list from a list literal, like this:\n",
    "\n",
    "  ```mojo\n",
    "  # Doesn't work!\n",
    "  var list: List[Int] = [2, 3, 5]\n",
    "  ```\n",
    "\n",
    "  But you can use variadic arguments to achieve the same thing:\n",
    "\n",
    "  ```mojo\n",
    "  var list = List(2, 3, 5)\n",
    "  ```\n",
    "\n",
    "- You can't `print()` a list, or convert it directly into a string.\n",
    "\n",
    "  ```mojo\n",
    "  # Does not work\n",
    "  print(list)\n",
    "  ```\n",
    "\n",
    "  As shown above, you can print the individual elements in a list as long as\n",
    "  they're a [`Stringable`](/mojo/stdlib/builtin/str/Stringable) type.\n",
    "\n",
    "- Iterating a `List` currently returns a \n",
    "  [`Reference`](/mojo/stdlib/memory/reference/Reference) to each item, not the\n",
    "  item itself. You can access the item using the dereference operator, `[]`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2, 3, 4, "
     ]
    }
   ],
   "source": [
    "#: from collections import List\n",
    "var list = List(2, 3, 4)\n",
    "for item in list:\n",
    "      print(item[], end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "  Subscripting in to a list, however, returns the item directly—no need to \n",
    "  dereference:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2, 3, 4, "
     ]
    }
   ],
   "source": [
    "#: from collections import List\n",
    "#: var list = List[Int](2, 3, 4)\n",
    "for i in range(len(list)):\n",
    "    print(list[i], end=\", \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dict\n",
    "\n",
    "The [`Dict`](/mojo/stdlib/collections/dict/Dict) type is an associative array\n",
    "that holds key-value pairs. You can create a `Dict` by specifying the key type\n",
    "and value type as parameters, like this:\n",
    "\n",
    "```mojo\n",
    "var values = Dict[String, Float64]()\n",
    "```\n",
    "\n",
    "The dictionary's key type must conform to the \n",
    "[`KeyElement`](/mojo/stdlib/collections/dict/KeyElement) trait, and value \n",
    "elements must conform to the \n",
    "[`CollectionElement`](/mojo/stdlib/builtin/value/CollectionElement) trait.\n",
    "\n",
    "You can insert and remove key-value pairs, update the value assigned to a key,\n",
    "and iterate through keys, values, or items in the dictionary. \n",
    "\n",
    "The `Dict` iterators all yield references, so you need to use the dereference\n",
    "operator `[]` as shown in the following example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "plasticity 3.1000000000000001\n",
      "elasticity 1.3\n",
      "electricity 9.6999999999999993\n"
     ]
    }
   ],
   "source": [
    "from collections import Dict\n",
    "\n",
    "var d = Dict[String, Float64]()\n",
    "d[\"plasticity\"] = 3.1\n",
    "d[\"elasticity\"] = 1.3\n",
    "d[\"electricity\"] = 9.7\n",
    "for item in d.items():\n",
    "    print(item[].key, item[].value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Set\n",
    "\n",
    "The [`Set`](/mojo/stdlib/collections/set/Set) type represents a set of unique\n",
    "values. You can add and remove elements from the set, test whether a value \n",
    "exists in the set, and perform set algebra operations, like unions and \n",
    "intersections between two sets. \n",
    "\n",
    "Sets are generic and the element type must conform to the\n",
    "[`KeyElement`](/mojo/stdlib/collections/dict/KeyElement) trait."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "We both like:\n",
      "- ice cream\n",
      "- tacos\n"
     ]
    }
   ],
   "source": [
    "from collections import Set\n",
    "\n",
    "i_like = Set(\"sushi\", \"ice cream\", \"tacos\", \"pho\")\n",
    "you_like = Set(\"burgers\", \"tacos\", \"salad\", \"ice cream\")\n",
    "we_like = i_like.intersection(you_like)\n",
    "\n",
    "print(\"We both like:\")\n",
    "for item in we_like:\n",
    "    print(\"-\", item[])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Optional\n",
    "\n",
    "An [`Optional`](/mojo/stdlib/collections/optional/Optional)  represents a \n",
    "value that may or may not be present. Like the other collection types, it is\n",
    "generic, and can hold any type that conforms to the\n",
    "[`CollectionElement`](/mojo/stdlib/builtin/value/CollectionElement) trait."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Two ways to initialize an Optional with a value\n",
    "var opt1 = Optional(5)\n",
    "var opt2: Optional[Int] = 5\n",
    "# Two ways to initalize an Optional with no value\n",
    "var opt3 = Optional[Int]()\n",
    "var opt4: Optional[Int] = None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "An `Optional` evaluates as `True` when it holds a value, `False` otherwise. If\n",
    "the `Optional` holds a value, you can retrieve a reference to the value using \n",
    "the `value()` method. But calling `value()` on an `Optional` with no value\n",
    "results in undefined behavior, so you should always guard a call to `value()`\n",
    "inside a conditional that checks whether a value exists."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Testing\n"
     ]
    }
   ],
   "source": [
    "var opt: Optional[String] = str(\"Testing\")\n",
    "if opt:\n",
    "    var value_ref = opt.value()\n",
    "    print(value_ref)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Alternately, you can use the `or_else()` method, which returns the stored\n",
    "value if there is one, or a user-specified default value otherwise:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello\n",
      "Hi\n"
     ]
    }
   ],
   "source": [
    "var custom_greeting: Optional[String] = None\n",
    "print(custom_greeting.or_else(\"Hello\"))\n",
    "\n",
    "custom_greeting = str(\"Hi\")\n",
    "print(custom_greeting.or_else(\"Hello\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Register-passable, memory-only, and trivial types\n",
    "\n",
    "In various places in the documentation you'll see references to \n",
    "register-passable, memory-only, and trivial types. Register-passable and \n",
    "memory-only types are distinguished based on how they hold data:\n",
    "\n",
    "- Register-passable types are composed exclusively of fixed-size data types,\n",
    "  which can (theoretically) be stored in a machine register. A register-passable\n",
    "  type can include other types, as long as they are also register-passable.\n",
    "  `Int`, `Bool`, and `SIMD`, for example, are all register-passable types. So \n",
    "  a register-passable `struct` could include `Int` and `Bool` fields, but not a\n",
    "  `String` field. Register-passable types are declared with the \n",
    "  [`@register_passable`](/mojo/manual/decorators/register-passable) decorator.\n",
    "\n",
    "  Register-passable types are always passed by value (that is, the values are\n",
    "  copied).\n",
    "\n",
    "- Memory-only types consist of any types that _don't_ fit the description of\n",
    "  register-passable types. In particular, these types usually have pointers or \n",
    "  references to dynamically-allocated memory. `String`, `List`, and `Dict` are\n",
    "  all examples of memory-only types.\n",
    "\n",
    "Our long-term goal is to make this distinction transparent to the user, and\n",
    "ensure all APIs work with both register-passable and memory-only types.\n",
    "But right now you will see some standard library types that only work with \n",
    "register-passable types or only work with memory-only types.\n",
    "\n",
    "In addition to these two categories, Mojo also has \"trivial\" types. Conceptually\n",
    "a trivial type is simply a type that doesn't require any custom logic in its\n",
    "lifecycle methods. The bits that make up an instance of a trivial type can be\n",
    "copied or moved without any knowledge of what they do. Currently, trivial types\n",
    "are declared using the\n",
    "[`@register_passable(trivial)`](/mojo/manual/decorators/register-passable#register_passabletrivial)\n",
    "decorator. Trivial types shouldn't be limited to only register-passable types,\n",
    "so in the future we intend to separate trivial types from the \n",
    "`@register_passable` decorator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `AnyType` and `AnyTrivialRegType`\n",
    "\n",
    "Two other things you'll see in Mojo APIs are references to `AnyType` and\n",
    "`AnyTrivialRegType`. These are effectively _metatypes_, that is, types of types.\n",
    "\n",
    "- `AnyType` represents any Mojo type. Mojo treats `AnyType` as a special kind of\n",
    "  trait, and you'll find more discussion of it on the\n",
    "  [Traits page](/mojo/manual/traits#the-anytype-trait).\n",
    "- `AnyTrivialRegType` is a metatype representing any Mojo type that's marked \n",
    "  register passable.\n",
    "\n",
    "You'll see them in signatures like this:\n",
    "\n",
    "```mojo\n",
    "fn any_type_function[ValueType: AnyTrivialRegType](value: ValueType):\n",
    "    ...\n",
    "```\n",
    "\n",
    "You can read this as `any_type_function` has an argument, `value` of type\n",
    "`ValueType`, where `ValueType` is a register-passable type, determined at\n",
    "compile time. \n",
    "\n",
    "There is still some code like this in the standard library, but it's gradually\n",
    "being migrated to more generic code that doesn't distinguish between \n",
    "register-passable and memory-only types.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
